/*
 * Copyright 2023-2025, Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 *
 * 龙芯LoongArch64架构SMP多处理器支持实现
 * 本文件实现龙芯平台的SMP支持，包括处理器间中断(IPI)机制
 */

#include <KernelExport.h>

#include <arch/smp.h>
#include <boot/kernel_args.h>
#include <device_manager.h>
#include <int.h>
#include <smp.h>
#include <vm/vm.h>

// 定义调试输出宏
#define TRACE_SMP
#ifdef TRACE_SMP
#define TRACE(x...) dprintf("arch_smp_loongson: " x)
#else
#define TRACE(x...) ;
#endif

// 龙芯平台IPI寄存器定义
#define LOONGSON_IPI_BASE       0x1fe01000  // IPI寄存器基地址
#define LOONGSON_IPI_SET_OFFSET 0x00        // 设置IPI寄存器偏移
#define LOONGSON_IPI_CLR_OFFSET 0x04        // 清除IPI寄存器偏移
#define LOONGSON_IPI_STS_OFFSET 0x08        // 状态IPI寄存器偏移

// IPI消息类型
#define IPI_MSG_RESCHEDULE      0x01        // 重新调度
#define IPI_MSG_INVALIDATE_TLB  0x02        // 无效化TLB
#define IPI_MSG_STOP            0x04        // 停止CPU
#define IPI_MSG_CALL_FUNCTION   0x08        // 调用函数

// 全局变量
static addr_t sIpiBase = 0;                 // IPI寄存器基地址
static uint32 sMaxCpus = 0;                 // 最大CPU数量

// 读取IPI寄存器
static inline uint32
read_ipi_reg(uint32 cpu, uint32 offset)
{
    return *(volatile uint32 *)(sIpiBase + (cpu * 0x10) + offset);
}

// 写入IPI寄存器
static inline void
write_ipi_reg(uint32 cpu, uint32 offset, uint32 value)
{
    *(volatile uint32 *)(sIpiBase + (cpu * 0x10) + offset) = value;
}

// 初始化龙芯平台SMP
status_t
loongson_smp_init(kernel_args *args)
{
    TRACE("Initializing Loongson SMP\n");

    // 获取IPI寄存器基地址
    sIpiBase = args->arch_args.extioi.start;
    if (sIpiBase == 0) {
        dprintf("Loongson SMP: No IPI register base address found!\n");
        return B_ERROR;
    }

    // 获取最大CPU数量
    sMaxCpus = args->num_cpus;
    if (sMaxCpus > SMP_MAX_CPUS)
        sMaxCpus = SMP_MAX_CPUS;

    TRACE("IPI base address: %#" B_PRIxADDR ", max CPUs: %u\n", sIpiBase, sMaxCpus);

    // 清除所有CPU的IPI状态
    for (uint32 cpu = 0; cpu < sMaxCpus; cpu++) {
        write_ipi_reg(cpu, LOONGSON_IPI_CLR_OFFSET, 0xffffffff);
    }

    return B_OK;
}

// 初始化每个CPU的SMP
status_t
loongson_smp_per_cpu_init(kernel_args *args, int32 cpu)
{
    TRACE("Initializing SMP for CPU %d\n", cpu);

    // 清除当前CPU的IPI状态
    write_ipi_reg(cpu, LOONGSON_IPI_CLR_OFFSET, 0xffffffff);

    return B_OK;
}

// 发送多播IPI
void
loongson_smp_send_multicast_ici(CPUSet &cpuSet)
{
    uint32 currentCpu = smp_get_current_cpu();

    for (uint32 cpu = 0; cpu < sMaxCpus; cpu++) {
        if (cpu != currentCpu && cpuSet.GetBit(cpu)) {
            // 发送IPI_MSG_CALL_FUNCTION消息
            write_ipi_reg(cpu, LOONGSON_IPI_SET_OFFSET, IPI_MSG_CALL_FUNCTION);
        }
    }
}

// 发送单播IPI
void
loongson_smp_send_ici(int32 targetCpu)
{
    if (targetCpu >= 0 && targetCpu < (int32)sMaxCpus) {
        // 发送IPI_MSG_RESCHEDULE消息
        write_ipi_reg(targetCpu, LOONGSON_IPI_SET_OFFSET, IPI_MSG_RESCHEDULE);
    }
}

// 发送广播IPI
void
loongson_smp_send_broadcast_ici()
{
    uint32 currentCpu = smp_get_current_cpu();

    for (uint32 cpu = 0; cpu < sMaxCpus; cpu++) {
        if (cpu != currentCpu) {
            // 发送IPI_MSG_CALL_FUNCTION消息
            write_ipi_reg(cpu, LOONGSON_IPI_SET_OFFSET, IPI_MSG_CALL_FUNCTION);
        }
    }
}

// 处理IPI中断
void
loongson_smp_handle_ipi(int32 cpu)
{
    // 读取IPI状态
    uint32 status = read_ipi_reg(cpu, LOONGSON_IPI_STS_OFFSET);
    
    // 清除IPI状态
    write_ipi_reg(cpu, LOONGSON_IPI_CLR_OFFSET, status);

    // 处理各种IPI消息
    if (status & IPI_MSG_RESCHEDULE) {
        // 重新调度
        smp_intercpu_int_handler(B_RESCHEDULE_INTERRUPT);
    }

    if (status & IPI_MSG_INVALIDATE_TLB) {
        // 无效化TLB
        arch_cpu_global_TLB_invalidate();
    }

    if (status & IPI_MSG_STOP) {
        // 停止CPU
        smp_intercpu_int_handler(B_SHUTDOWN_INTERRUPT);
    }

    if (status & IPI_MSG_CALL_FUNCTION) {
        // 调用函数
        smp_intercpu_int_handler(B_INTERRUPT_INTERRUPT);
    }
}